﻿<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
	<title>event - test</title>
	<script type="text/javascript">
var expando = '@event' + (new Date).getTime(),

preventDefault = function()
{
    this.returnValue = false;
},

stopPropagation = function()
{
    this.cancelBubble = true;
};

var cache =
{
    guid: 0, fuid: 0,
	
	func: function(uid)
	{
	    return function(){
		    try{
			    oneEvent.handle.apply( cache[uid].elem, arguments );
			}catch(e){};
		};
	}
};

var oneEvent =
{
	add: function( elem, type, handler )
	{
	    var guid = elem[expando] || (elem[expando] = ++cache.guid);
		
		if( !cache[guid] )
		{
		    cache[guid] = {
			    elem: elem,
				listener: cache.func(guid),
				events: {}
			};
		}
		
		if( type && !cache[guid].events[type] )
		{
		    cache[guid].events[type] = [];
			
			elem.addEventListener
			? elem.addEventListener(type, cache[guid].listener, false)
			: elem.attachEvent('on' + type, cache[guid].listener);
		}
		
		if( handler )
		{
		    if( !handler.fuid )
			    handler.fuid = ++cache.fuid;
			cache[guid].events[type].push( handler );
		}
		
		elem = null;
	},
	
	remove: function( elem, type, handler )
	{
	    var handlers, events, ret, eventType, handlerObj;
		
		try{
		    handlers = cache[ elem[expando] ];
		}catch(e){ return; };
		
		if( !handlers ) return;
		events = handlers.events;
		
		if( type === undefined )
		{
		    for( var type in events )
			    oneEvent.remove( elem, type );
			return;
		}
		
		eventType = events[type];
		
		if( eventType )
		{
		    if( handler )
			{
			    for( var i = 0; i < eventType.length; i++ )
				{
				    handlerObj = eventType[i];
					if( handler.fuid === handlerObj.fuid )
					    eventType.splice( i--, 1 );
				}
			}
			else
			{
			    for( var i = 0; i < eventType.length; i++ )
				    eventType.splice( i--, 1 );
			}
			
			for( ret in events[type] ) break;
			if( !ret )
			{
			    elem.removeEventListener
				? elem.removeEventListener(type, handlers.listener, false)
				: elem.detachEvent('on' + type, handlers.listener);
				
				ret = null;
				delete events[type];
			}
		}
		
		for( ret in events ) break;
		if( !ret )
		{
			handlers.elem = null;
			delete cache[ elem[expando] ];
			
			try{
			    delete elem[expando];
			}catch(e){
			    elem.removeAttribute && elem.removeAttribute(expando);
			};
		}
	},
	
	handle: function(event)
	{
	    event = oneEvent.fix( event || window.event );
		
		if( !event.currentTarget )
		    event.currentTarget = this;
		
		var handlers = cache[this[expando]].events[event.type].slice(0),
		    i = 0, l = handlers.length, handleObj;
		
		for( ; i < l; i++ )
		{
		    handleObj = handlers[i];
			
			if( handleObj.call(this, event) === false )
			{
			    event.preventDefault();
				event.stopPropagation();
			}
		}
	},
	
	fix: function(event)
	{
	    if( event.target ) return event;
		
		event.preventDefault = preventDefault;
		event.stopPropagation = stopPropagation;
		event.target = event.srcElement || document;
		
		return event;
	}
};

// demo
window.onload = function()
{
    var el = document.getElementById('title');
	
	oneEvent.add( el, 'click', function(ev){ alert(ev.target.id); });
	oneEvent.add( el, 'click', function(ev){ alert(ev.target.style.height); });
	
	oneEvent.remove( el, 'click' );
};
	</script>
</head>

<body>
    <div id="iDiv" style="position:absolute;top:50px;left:200px;border:3px solid #f00;width:300px;height:200px;">
	    <div id="title" style="height:28px;background:#00f;margin:2px;"></div>
	</div>
</body>
</html>